package com.yifushidai.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;

/**
 * @Description: 进制转换工具类，常用为十六进制 二进制 八进制 字符串 byte及数组转换
 */
public class HexUtils {

    private static Logger logger = LoggerFactory.getLogger(HexUtils.class);

    @SuppressWarnings("unused")
    private static final String PATTERN_LEN_TEN = "0000000000";// Len(2^32)=10

    private static final DecimalFormat numberformater = new DecimalFormat();

    /**
     * hex to char
     *
     * @param arg0 two number orgnized to hex string
     * @return char
     */
    public static char toChar(String arg0) {
        return Character.toChars(Integer.parseInt(arg0, 16))[0];
    }

    /**
     * hex string to int
     *
     * @param arg0
     * @return
     */
    public static int toInt(String arg0) {
        return Integer.parseInt(arg0, 16);
    }

    /**
     * hex string to binary string
     *
     * @param hexstr
     * @param radix
     * @return
     */
    public static String toBinaryStr(String hexstr, int radix) {
        String binstr = Integer.toBinaryString(Integer.parseInt(hexstr, 16));
        StringBuffer b = new StringBuffer(binstr);

        while (b.length() < radix) {
            b.insert(0, '0');
        }
        return b.toString();
    }

    /**
     * hex string to binary string, format to 32 char
     *
     * @param hexstr
     * @return
     */
    public static String toBinaryStr32(String hexstr) {
        int radix = 16;

        String binstr = Long.toBinaryString(Long.parseLong(hexstr, radix));
        ;
        StringBuffer b = new StringBuffer(binstr);
        while (b.length() < radix) {
            b.insert(0, '0');
        }
        return b.toString();
    }

    /**
     * binary to String, 16 chars
     *
     * @return
     */
    public static String toBinaryStr16(String hexstr) {
        return toBinaryStr(hexstr, 16);
    }

    /**
     * binary to String, 8 chars
     *
     * @return
     */
    public static String toBinaryStr8(byte bin) {
        String binstr = Integer.toBinaryString(bin);
        StringBuffer b = new StringBuffer(binstr);

        while (b.length() < 8) {
            b.insert(0, '0');
        }
        return b.toString();
    }

    /**
     * binary String to hex byte array
     *
     * @return
     */
    public static byte[] binaryStrToHexByte(String val) {
        int bi2 = Integer.parseInt(val, 2);
        numberformater.applyPattern("00000000");
        int res_16 = Integer.valueOf(Integer.toHexString(bi2));
        String result = numberformater.format(res_16);
        byte[] b = HexUtils.hexStringToBytes(result);
        return b;
    }

    /**
     * String to hex String
     */
    public static String str2HexStr(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
        }
        return sb.toString();
    }

//    /**
//     * bytes to int
//     *
//     * @param b
//     * @return
//     */
//    public static int bytesToInt(byte[] b) {
//        int mask = 0xff;
//        int temp;
//        int n = 0;
//        for (int i = 0; i < b.length; i++) {
//            n <<= 8;
//            temp = b[i] & mask;
//            n |= temp;
//        }
//        return n;
//    }

    /**
     * string to hex string
     *
     * @return
     */
    public static String stringToHexString(String string) {
        return HexUtils.bytesToHexString(string.getBytes());
    }

    /**
     * int to byte[], length=1
     *
     * @param intValue
     * @return
     */
    public static byte[] intToSimpleByteArray(int intValue) {
        byte[] result = null;
        if (intValue <= 255) {
            result = new byte[1];
            result[0] = (byte) (intValue & 0xFF);
        }
        return result;
    }

    /**
     * int 转 byte数组， 2个字节或者4个字节 int to byte[], length=2,4
     *
     * @param intValue
     * @return
     */
    public static byte[] intToByteArray(int intValue) {
        byte[] result = null;
        if (intValue <= 65535) {
            result = new byte[2];
            result[0] = (byte) (intValue & 0x00FF);//低字节在前
            result[1] = (byte) ((intValue & 0xFF00) >> 8);
        } else if (intValue > 65535 && intValue <= Integer.MAX_VALUE) {
            result = new byte[4];
            result[0] = (byte) ((intValue & 0xFF000000) >> 24);
            result[1] = (byte) ((intValue & 0x00FF0000) >> 16);
            result[2] = (byte) ((intValue & 0x0000FF00) >> 8);
            result[3] = (byte) ((intValue & 0x000000FF));
        }
        return result;
    }

    /**
     * int 转 byte数组， 4个字节
     *
     * @param intValue
     * @return
     */
    public static byte[] intToByte4Array(int intValue) {
        byte[] result = null;
        if (intValue <= 65535) {
            result = new byte[4];
            result[0] = 0x00;
            result[1] = 0x00;
            result[2] = (byte) ((intValue & 0xFF00) >> 8);
            result[3] = (byte) (intValue & 0x00FF);
        } else if (intValue > 65535 && intValue <= Integer.MAX_VALUE) {
            result = new byte[4];
            result[0] = (byte) ((intValue & 0xFF000000) >> 24);
            result[1] = (byte) ((intValue & 0x00FF0000) >> 16);
            result[2] = (byte) ((intValue & 0x0000FF00) >> 8);
            result[3] = (byte) ((intValue & 0x000000FF));
        }
        return result;
    }

    /**
     * int转byte数组，3个字节 int to byte[], length=3
     *
     * @param intValue
     * @return
     */
    public static final byte[] intToThreeByteArray(int intValue) {
        byte[] result = null;
        if (intValue > 65535 && intValue <= 16777215) {
            result = new byte[3];
            result[0] = (byte) ((intValue & 0xFF0000) >> 16);
            result[1] = (byte) ((intValue & 0x00FF00) >> 8);
            result[2] = (byte) ((intValue & 0x0000FF));
        }
        return result;
    }

    /**
     * int 转数组，有符号，单字节 int to byte[], contain sign
     *
     * @param signIntVal
     * @return
     */
    public static final byte[] intToSignByteArray(int signIntVal) {
        byte[] b = HexUtils.intToByteArray(Math.abs(signIntVal));

        if (signIntVal < 0) {
            b[0] = (byte) 0x80;
        }
        return b;
    }

    /**
     * 源自JDK1.6的方法，从一个byte[]数组中复制byte
     *
     * @since 1.6
     */
    public static byte[] copyOfRange(byte[] original, int from, int to) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        byte[] copy = new byte[newLength];
        System.arraycopy(original, from, copy, 0, Math.min(original.length
                - from, newLength));
        return copy;
    }

    /**
     * short to byte[]
     *
     * @param n
     * @return
     */
    public static byte[] shortToBytes(short n) {
        byte[] b = new byte[2];
        b[1] = (byte) (n & 0xff);
        b[0] = (byte) ((n >> 8) & 0xff);
        return b;
    }

    /**
     * 中文转unicode编码
     */
    public static String chinese2unicode(final String chineseStr) {
        char[] utfBytes = chineseStr.toCharArray();
        String unicodeBytes = "";
        for (char utfByte : utfBytes) {
            String hexB = Integer.toHexString(utfByte);
            if (hexB.length() <= 2) {
                hexB = "00" + hexB;
            }
            unicodeBytes = unicodeBytes + "\\u" + hexB;
        }
        return unicodeBytes;
    }

    /**
     * unicode编码转中文
     */
    public static String unicode2chinese(final String unicodeStr) {
        int start = 0;
        int end = 0;
        final StringBuilder buffer = new StringBuilder();
        while (start > -1) {
            end = unicodeStr.indexOf("\\u", start + 2);
            String charStr = "";
            if (end == -1) {
                charStr = unicodeStr.substring(start + 2, unicodeStr.length());
            } else {
                charStr = unicodeStr.substring(start + 2, end);
            }
            char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串。
            buffer.append(Character.toString(letter));
            start = end;
        }
        return buffer.toString();
    }

    /**
     * hexStr转unicode编码
     */
    public static String hexStr2unicode(String hexStr) {
        String[] hexStrArray = hexStr.split("\\s");
        StringBuilder sb = new StringBuilder();
        String tmp = "";
        for (int i = 0; i < hexStrArray.length; i++) {
            if (i % 2 == 0) {
                tmp = hexStrArray[i];
                hexStrArray[i] = hexStrArray[i + 1];
                sb.append("\\u").append(hexStrArray[i]);
            } else {
                hexStrArray[i] = tmp;
                sb.append(hexStrArray[i]);
            }
        }
        return sb.toString();
    }

    /**
     * 	基本信息处理
     * 因为二代身份证里编码为GB13000，在java处理中存在问题，总体处理思想为先把16进制字节高地位互换，然后用UTF-16BE转换成中文字符代码如下
     *
     * @param bytes
     * @param charsetName
     * @return
     */
    public static String hexByes2String(byte[] bytes, String charsetName) {
        if ("".equals(charsetName)) charsetName = "UTF-16BE";
        try {
            return new String(bytes, charsetName);
        } catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
            e.printStackTrace();
        }
        return "";
    }

    public static byte[] hexBytesH2L(byte[] bytes) {
        byte tmp = 0;
        for (int i = 0; i < bytes.length; i++) {
            if (i % 2 == 0) {
                tmp = bytes[i];
                bytes[i] = bytes[i + 1];
            } else {
                bytes[i] = tmp;
            }
        }
        return bytes;
    }

    public static byte[] hexToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }

        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] bytes = new byte[length];
        String hexDigits = "0123456789abcdef";
        for (int i = 0; i < length; i++) {
            int pos = i * 2; // 两个字符对应一个byte
            int h = hexDigits.indexOf(hexChars[pos]) << 4; // 注1
            int l = hexDigits.indexOf(hexChars[pos + 1]); // 注2
            if (h == -1 || l == -1) { // 非16进制字符
                return null;
            }
            bytes[i] = (byte) (h | l);
        }
        return bytes;
    }

    public static byte[] getBytes(String cmd) {
        String[] cmds = cmd.split(" ");
        byte[] aaa = new byte[cmds.length];
        int i = 0;
        for (String b : cmds) {
            if (b.equals("FF")) {
                aaa[i++] = -1;
            } else {
                aaa[i++] = Byte.parseByte(b, 16);
            }
        }
        return aaa;
    }

    public static byte[] getBytes2(String cmd) {
        String[] cmds = cmd.split(" ");
        byte[] aaa = new byte[cmds.length];
        int i = 0;
        for (String b : cmds) {
            if (b.equals("FF")) {
                aaa[i++] = -1;
            } else {
                aaa[i++] = (byte) Integer.parseInt(b, 16);
            }
        }
        return aaa;
    }

    /**
     * byte[] 与 gbk 转换
     */
    public static byte[] encodeGBK(String gbkString) {
        try {
            return gbkString.getBytes("GBK");
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(), e);
        }
        return new byte[0];
    }

    public static String decodeGBK(byte[] b) {
        try {
            return new String(b, "GBK");
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(), e);
        }
        return "";
    }

    /**
     * byte[] 与 utf-16 big endian 转换
     */
    public static byte[] encodeUTF16BE(String utf16beString) {
        try {
            return utf16beString.getBytes("UTF-16BE");
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(), e);
        }
        return new byte[0];
    }

    public static String decodeUTF16BE(byte[] b) {
        try {
            return new String(b, "UTF-16BE");
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(), e);
        }
        return "";
    }

    /**
     * byte[] 与 utf-16 little endian 转换
     */
    public static byte[] encodeUTF16LE(String utf16leString) {
        try {
            return utf16leString.getBytes("UTF-16LE");
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(), e);
        }
        return new byte[0];
    }

    public static String decodeUTF16LE(byte[] b) {
        try {
            return new String(b, "UTF-16LE");
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(), e);
        }
        return "";
    }

    /**
     * byte 与 int 转换
     */
    public static byte int2Byte(int a) {
        return (byte) a;
    }

    public static int byte2Int(byte b) {
        //Java 总是把 byte 当做有符处理；我们可以通过将其和 0xFF 进行二进制与得到它的无符值
        return b & 0xFF;
    }

    /**
     * byte[] 与 int 转换
     */
    public static int bytes2Int(byte[] b) {
        switch (b.length) {
            case 2:
                return b[0] & 0xFF | //低字节在前
                        (b[1] & 0xFF) << 8;
            case 4:
                return b[3] & 0xFF |
                        (b[2] & 0xFF) << 8 |
                        (b[1] & 0xFF) << 16 |
                        (b[0] & 0xFF) << 24;
            default:
                return -1;
        }
    }

    public static byte[] int2Bytes(int a) {
        byte[] result = null;
        if (a <= 65535) {
            result = new byte[2];
            result[0] = (byte) (a & 0xFF);//低字节在前
            result[1] = (byte) ((a >> 8) & 0xFF);
        } else if (a > 65535) {
            result = new byte[4];
            result[0] = (byte) ((a >> 24) & 0xFF);
            result[1] = (byte) ((a >> 16) & 0xFF);
            result[2] = (byte) ((a >> 8) & 0xFF);
            result[3] = (byte) (a & 0xFF);
        }
        return result;
    }

    /**
     * byte[] 与 hex string 转换
     */
    public static byte[] hexStringToBytes(String hexString) {
        hexString = hexString.toUpperCase();// 大小写转换，引起重视
        int len = (hexString.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hexString.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            int ten = toByte(achar[pos]);
            int one = toByte(achar[pos + 1]);
            result[i] = (byte) (ten << 4 | one);
        }
        return result;
    }

    public static String bytesToHexString(byte[] bytes) {
        StringBuffer sb = new StringBuffer(bytes.length);
        String sTemp;
        for (byte b : bytes) {
            sTemp = Integer.toHexString(0xFF & b);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    private static int toByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    public static void main(String[] args) {
        System.out.println(bytesToHexString(new byte[]{(byte) 0xA1}));
    }

}